// vim: ft=javascript

var myFloat = 0.123;
var myOctal = 0x123;
var myRegex = /asdf/;
var myComplicatedRegex = /.[.](?=x\h\[[)])[^.{}abc]{foo}{3,}x{2,3}/
var myObject = { a: 1, b: 2 }
var someText = "hi";
someText += "\nthere";

var test = 123

var foo = {
  a: "\test",
  b: "\nest",
  c: "\\test",
  d: "\\nest",
  e: "\\",
  f: "Using \\ in a string",
  g: "\error"
};

switch(test) {
case 123:
  console.log(123)
  break
default:
  console.log('default')
  break
}

switch(1) {
  case { foo: 1 }.foo:
    console.log('oh my fucking god')
    break
  case { bar: 2 }.bar ? baz: zot:

  case { zot: 3 }.zot ? { quux : 4 } .quux: 5:
    console.log('ahahahahahaha')

}

var ternary = 0 ? 1 : {object_key : 2 ? variable : 3 };
var ternary2 = a ? { object_key : c } + variable : e;
var ternary3 = a ? {
  key1 : var1,
  key2: var2 ? function() {
    label1: // break label, not an object key!
    while(true) {
      break label1;
    }

    label2: // also a break label
    while (true) {
      break label2;
    }
  } + var3: var4, // ternary, not object key
  key3: 'foo'
} : 2

var a = {
  num: 0,
  func: function() {},
  str: '',
  bool: true
}

var obj =
  {
    // comment
    key: val
  }

/*!
 * multiline comment
 */

var quotedKeys = {
  "one": 1,
  "two": 2,
  "three": 3,
};

var doc = {
  "first": {
    "key": "value",
    "func" : function() {
      label:
      while (true) break label;

      return foo ? "bar" : { baz: zot }

    }

  },
  "hello": "world"
};

// not an object is OK
var doc = {
  "first": "value",
  "hello": "world"
};

// not quoted is OK
var doc = {
  first: {
    "key": "value"
  },
  "hello": "world"
};
Blag = {};
jQuery.noConflict();

if (cond)
{
  label1:
  while (cond) break label1;
}

Blag.ReadMore = (function($) {
  function getFold(button) {
    return $(button).siblings('.fold');
  }

  function expand(e) {
    e.preventDefault();

    var self = $(this);

    getFold(self).show();
    self.html('&laquo; less');
  }

  function contract(e) {
    e.preventDefault();

    var self = $(this);

    getFold(self).hide();
    self.html('more &raquo;')
  }

  function init() {
    $('a.read-more').toggle(expand, contract);
  }

  $(document).ready(init);
})(jQuery);

underscoreFunc = _underscoreFunc()
underscoreClass = _UnderscoreClass()

// evil regexes, from pygments

/regexp/.test(foo) || x = [/regexp/,/regexp/, /regexp/, // comment
// comment
/regexp/];
if (/regexp/.test(string))
{/regexp/.test(string);};
x =/regexp/;
x = /regexp/;
if (0</regexp/.exec(string) || 1>/regexp/.exec(string))
x = { u:/regexp/, v: /regexp/ };
foo();/regexp/.test(string); /regexp/.test(string);
if (!/regexp/) foobar();
x = u %/regexp/.exec(string) */regexp/.exec(string) / /regexp/.exec(string);
x = u?/regexp/.exec(string) : v +/regexp/.exec(string) -/regexp/.exec(string);
a = u^/regexp/.exec(string) &/regexp/.exec(string) |/regexp/.exec(string) +~/regexp/.exec(string);
x = /regexp/ /* a comment */ ;
x = /[reg/exp]/;
x = 4/2/i;
x = (a == b) ?/* this is a comment */ c : d;
/// a comment //
a = /regex//2/1; //syntactically correct, returns NaN

// bad regexen - should have an error token at the last char and recover
// on the next line
var a = /foo
var b = /[foo
var c = /valid-regex/

var template = "{{current}} of beer on the wall";
var stanza = template.replace(/{{current}}/g, "99 bottles");

/* original examples */

// regex

blah(/abc/);
x = /abc/;
x = /abc/.match;

// math

blah(1/2); //comment
x = 1 / 2 / 3;
x = 1/1/.1;

x=/1/; // regex
x=1/a/g; // division
x=a/a/g; // division

// real-world

var x = 1/(1+Math.sqrt(sum)); // convert to number between 1-0
return Math.round((num / den) * 100)/100;

// generator
function* range(from, to)
{
  to++;
  while (from > to) {
    yield from++;
  }
}

// string interpolation
`this is ${"sparta".toUpperCase()}`;

// nasty string interpolation
`this\n \` \${2} $\` is\n ${"sparta".toUpperCase() + function() { return 4; } + "h"}`;
`hello ${"${re}" + `curs${1}on`}`;

`$`;
`$${1 + 2 + 3}`;

`${
  'multiline template'
}`;
`${
  1 + 2
}`;

var notATernary = `${obj?.prop}`;

@(function(thing) { return thing; })
class Person {
  @deprecate
  facepalm() {}

  @deprecate('We stopped facepalming')
  facepalmHard() {}

  @deprecate('We stopped facepalming', { url: 'http://knowyourmeme.com/memes/facepalm' })
  facepalmHarder() {}
}

// ES6 module
import * as foo from 'foo'
import { bar as baz } from 'bar'
export * from 'baz'
export function hoge() {}
export class fuga extends baz {
  constructor () {
    super()
  }
  async doit (stuff) {
    await stuff()
    this.dont(stuff)
  }
  dont (stuff) {
    return arguments.length
  }
}
eval('false')
global.foo = {
  * [Symbol.iterator] () { return }
}
for (const x of global.foo) {}

// ES6 numbers

var myBin   = 0b10;
var myOct   = 0o67;

// ES6 regexes

let x = /abc/u;
let x = /abc/y;

// Unicode example
class Œuvre {
  résumer(语言 = "français") {
    书名 = "Les Misérables";
  }
}

unicodeClass = Œuvre()

// Nullish coalescing operator (??)
let ret = "";
let foo, bar;

ret += `// ${foo ?? "Unk"}: ${bar ?? "Just do it"}`;
ret += "\n";

let baz;
baz ??= 'default';

class ClassWithPrivate {
  #privateField;
  #privateFieldWithInitializer = 42;

  #privateMethod(obj) {
    if (#privateField in obj) return obj.#privateField;

    return "invalid obj"
  }

  static #privateStaticField;
  static #privateStaticFieldWithInitializer = 42;

  static #privateStaticMethod() {
    // …
  }
}
